/**
 * This file is part of AppStoreBot.
 *
 * AppStoreBot is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * AppStoreBot is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with AppStoreBot.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package lu.pragmaconsult.appstorebot.itunes;

import static lu.pragmaconsult.appstorebot.itunes.Constants.DATE_FORMAT;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import lu.pragmaconsult.appstorebot.Bot;
import lu.pragmaconsult.appstorebot.BotContext;
import lu.pragmaconsult.appstorebot.ExitStatus;

import org.apache.commons.httpclient.HttpClient;

/**
 * 
 * A Bot implementation dedicated to <a
 * href="https://itunesconnect.apple.com/">iTunes Connect</a>.
 * 
 * @author Wilfried Vandenberghe (wilfried.vandenberghe at pragmaconsult.lu)
 */
public class ITunesConnectBot implements Bot {

	/**
	 * The current execution context
	 */
	private BotContext context;

	/**
	 * The bot state
	 */
	private BotState state;

	/**
	 * An HTTP client object.
	 */
	private HttpClient httpClient = new HttpClient();

	/*
	 * (non-Javadoc)
	 * 
	 * @see lu.pragmaconsult.appstorebot.itunes.BotState#run()
	 */
	@Override
	public Bot configure(BotContext context) throws IllegalArgumentException {
		this.context = context;
		
		LoggerUtils.setDebugEnabled(context.isDebug());

		validate();

		AbstractBotState state = null;
		if (context.isPasswordStdin()) {
			state = new PasswordFromInputBotState();
		} else {
			state = new ConnectBotState();
		}
		
		state.setBot(this);
		setState(state);

		return this;
	}

	/**
	 * {@link BotContext} validation.
	 */
	void validate() {
		// check apple ID
		if (context.getAppleId() == null) {
			throw new NullPointerException("Apple ID is mandatory");
		}
		if (context.getAppleId().length() == 0) {
			throw new IllegalArgumentException("Apple ID is mandatory");
		}

		// check password
		if (!context.isPasswordStdin()) {
			if (context.getPassword() == null) {
				throw new NullPointerException(
						"Password is mandatory or should be asked (-P)");
			}
			if (context.getPassword().length() == 0) {
				throw new IllegalArgumentException(
						"Password is mandatory or should be asked (-P)");
			}
		}

		// check date format
		if (context.getDate() != null) {
			try {
				SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);
				format.parse(context.getDate());
			} catch (ParseException e) {
				throw new IllegalArgumentException(
						"Bad date format (mm/dd/yyyy): " + context.getDate());
			}
		}

		// check output directory existence and is a directory
		if (context.getOutputDiretory() != null) {
			File dir = new File(context.getOutputDiretory());
			if (!dir.exists()) {
				throw new IllegalArgumentException("Output directory: "
						+ context.getOutputDiretory() + " does not exist");
			}
			if (!dir.isDirectory()) {
				throw new IllegalArgumentException("Output directory: "
						+ context.getOutputDiretory() + " is not a directory");
			}
		}
	}

	/* (non-Javadoc)
	 * @see lu.pragmaconsult.appstorebot.Bot#run()
	 */
	@Override
	public ExitStatus run() {
		return state.run();
	}

	/**
	 * Only for test purpose.
	 * 
	 * @return the current bot state
	 */
	BotState getState() {
		return state;
	}

	/**
	 * Set the state to execute
	 * 
	 * @param state
	 *            to execute
	 */
	void setState(BotState state) {
		this.state = state;
	}

	/**
	 * Get the execution context.
	 * 
	 * @return execution context
	 */
	BotContext getBotContext() {
		return context;
	}

	/**
	 * Set {@link BotContext}. Only for test purpose.
	 * 
	 * @param context
	 *            bot context
	 */
	void setContext(BotContext context) {
		this.context = context;
	}

	/**
	 * Get the http client object.
	 * 
	 * @return http client object
	 */
	HttpClient getHttpClient() {
		return httpClient;
	}

	/**
	 * Only for test purpose.
	 * 
	 * @param client
	 *            http client object
	 */
	void setHttpClient(HttpClient client) {
		this.httpClient = client;
	}

}
